package com.ittao.taoaicodemother.core;

import cn.hutool.json.JSONUtil;
import com.ittao.taoaicodemother.ai.AiCodeGeneratorService;
import com.ittao.taoaicodemother.ai.AiCodeGeneratorServiceFactory;
import com.ittao.taoaicodemother.ai.model.HtmlCodeResult;
import com.ittao.taoaicodemother.ai.model.MultiFileCodeResult;
import com.ittao.taoaicodemother.ai.model.message.AiResponseMessage;
import com.ittao.taoaicodemother.ai.model.message.ToolExecutedMessage;
import com.ittao.taoaicodemother.ai.model.message.ToolRequestMessage;
import com.ittao.taoaicodemother.core.builder.VueProjectBuilder;
import com.ittao.taoaicodemother.core.parser.CodeParserExecutor;
import com.ittao.taoaicodemother.core.saver.CodeFileSaverExecutor;
import com.ittao.taoaicodemother.core.saver.CodeSaveResult;
import com.ittao.taoaicodemother.exception.BusinessException;
import com.ittao.taoaicodemother.exception.ErrorCode;
import com.ittao.taoaicodemother.manage.storage.factory.FileStorageStrategyFactory;
import com.ittao.taoaicodemother.manage.storage.lifecycle.ProjectLifecycleManager;
import com.ittao.taoaicodemother.manage.storage.strategy.FileStorageStrategy;
import com.ittao.taoaicodemother.model.entity.App;
import com.ittao.taoaicodemother.model.entity.User;
import com.ittao.taoaicodemother.model.enums.CodeGenTypeEnum;
import com.ittao.taoaicodemother.model.enums.UserRoleEnum;
import com.ittao.taoaicodemother.service.AppService;
import com.ittao.taoaicodemother.service.VipLimitService;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.service.TokenStream;
import dev.langchain4j.service.tool.ToolExecution;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * AI 代码生成器门面类，组合代码生成和保存功能
 */
@Service
@Slf4j
public class AiCodeGeneratorFacade {

    @Resource
    private AiCodeGeneratorServiceFactory aiCodeGeneratorServiceFactory;

    @Resource
    private VipLimitService vipLimitService;

    @Resource
    private AppService appService;

    @Resource
    private FileStorageStrategyFactory fileStorageStrategyFactory;

    @Resource
    private ProjectLifecycleManager projectLifecycleManager;

    @Resource
    private VueProjectBuilder vueProjectBuilder;

    /**
     * 统一入口，根据类型生成并保存代码
     * @param userMessage 用户提示词
     * @param codeGenType 生成类型
     * @param appId 应用 ID
     * @return 保存的目录结果
     */
    public CodeSaveResult generateAndSaveCode(String userMessage, CodeGenTypeEnum codeGenType, Long appId) {
        if (codeGenType == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, " 代码生成类型不能为空");
        }
        // 根据 appId 获取对应的 AiCodeGeneratorService 服务实例
        AiCodeGeneratorService aiCodeGeneratorService = aiCodeGeneratorServiceFactory.getAiCodeGeneratorService(appId, codeGenType);
        Long userId = getUserIdByAppId(appId);
        return switch (codeGenType) {
            case HTML -> {
                HtmlCodeResult htmlCodeResult = aiCodeGeneratorService.generateHtmlCode(userMessage);
                yield CodeFileSaverExecutor.executeSaver(htmlCodeResult, CodeGenTypeEnum.HTML, appId, userId);
            }
            case MULTI_FILE -> {
                MultiFileCodeResult multiFileCodeResult = aiCodeGeneratorService.generateMultiFileCode(userMessage);
                yield CodeFileSaverExecutor.executeSaver(multiFileCodeResult, CodeGenTypeEnum.MULTI_FILE, appId, userId);
            }
            default -> {
                String errorMessage = "不支持的生成类型" + codeGenType.getValue();
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, errorMessage);
            }
        };
    }

    /**
     * 统一入口，根据类型生成并保存代码（流式）
     * @param userMessage 用户提示词
     * @param codeGenType 生成类型
     * @param appId 应用 ID
     * @param user 当前用户
     * @return 保存的目录路径
     */
    public Flux<String> generateAndSaveCodeStream(String userMessage, CodeGenTypeEnum codeGenType, Long appId, User user) {
        if (codeGenType == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, " 代码生成类型不能为空");
        }

        // VIP 限制检查：Token容量限制
        int tokenCount = calculateTokenCount(userMessage);
        vipLimitService.checkTokenLimit(user, tokenCount);

        // 根据 appId 和用户信息获取对应的 AiCodeGeneratorService 服务实例（支持VIP限制）
        AiCodeGeneratorService aiCodeGeneratorService = aiCodeGeneratorServiceFactory.getAiCodeGeneratorService(appId, codeGenType, user);

        return switch (codeGenType) {
            case HTML -> {
                Flux<String> codeStream = aiCodeGeneratorService.generateHtmlCodeStream(userMessage);
                yield processCodeStream(codeStream, CodeGenTypeEnum.HTML, appId);
            }
            case MULTI_FILE -> {
                Flux<String> codeStream = aiCodeGeneratorService.generateMultiFileCodeStream(userMessage);
                yield processCodeStream(codeStream, CodeGenTypeEnum.MULTI_FILE, appId);
            }
            case VUE_PROJECT -> {
                TokenStream tokenStream;
                // 根据用户身份选择不同的接口
                if (isAdminOrVip(user)) {
                    tokenStream = aiCodeGeneratorService.generateVueProjectCodeStreamByAdminOrVip(appId, userMessage);
                } else {
                    tokenStream = aiCodeGeneratorService.generateVueProjectCodeStreamByUser(appId, userMessage);
                }
                yield processTokenStream(tokenStream, appId, user);
            }
        };
    }

    /**
     * 将 TokenStream 转换为 Flux<String>，并传递工具调用信息
     *
     * @param tokenStream TokenStream 对象
     * @return Flux<String> 流式响应
     */
    private Flux<String> processTokenStream(TokenStream tokenStream, Long appId, User user) {
        return Flux.create(sink -> {
            // 添加中断检查机制
            AtomicBoolean interrupted = new AtomicBoolean(false);
            tokenStream
                    .onPartialResponse((String partialResponse) -> {
                        if (!interrupted.get()) {
                            AiResponseMessage aiResponseMessage = new AiResponseMessage(partialResponse);
                            sink.next(JSONUtil.toJsonStr(aiResponseMessage));
                        }
                    })
                    .onPartialToolExecutionRequest((index, toolExecutionRequest) -> {
                        if (!interrupted.get()) {
                            ToolRequestMessage toolRequestMessage = new ToolRequestMessage(toolExecutionRequest);
                            sink.next(JSONUtil.toJsonStr(toolRequestMessage));
                        }
                    })
                    .onToolExecuted((ToolExecution toolExecution) -> {
                        if (!interrupted.get()) {
                            ToolExecutedMessage toolExecutedMessage = new ToolExecutedMessage(toolExecution);
                            sink.next(JSONUtil.toJsonStr(toolExecutedMessage));
                        }
                    })
                    .onCompleteResponse((ChatResponse response) -> {
                        if (!interrupted.get()) {
                            log.info("TokenStream 处理完成，响应 ID: {}", response.id());
                            // 获取用户ID构建项目路径
                            Long userId = user != null ? user.getId() : getUserIdByAppId(appId);
                            String sessionId = "session_" + appId + "_" + System.currentTimeMillis();

                            try {
                                // 检查项目是否生成成功（使用存储策略构建路径）
                                String projectName = "vue_project_" + appId;
                                FileStorageStrategy storageStrategy = fileStorageStrategyFactory.getCurrentStrategy();
                                String tempDirPath = storageStrategy.buildCodeOutputPath(String.valueOf(userId), projectName);
                                Path localTempPath = Paths.get(tempDirPath);

                                if (!localTempPath.toFile().exists()) {
                                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "非常抱歉，生成出了一点小差错，尝试更换模型再重新生成试试~~~");
                                }

                                // 在门面层执行Vue项目构建
                                boolean buildSuccess = vueProjectBuilder.buildProject(localTempPath);
                                if (!buildSuccess) {
                                    log.error("Vue项目构建失败，appId: {}", appId);
                                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "非常抱歉，生成出了一点小差错，尝试更换模型再重新生成试试~~~");
                                }
                                log.info("Vue项目构建成功，appId: {}", appId);

                                // 使用生命周期管理器处理后续流程：上传 → 延迟清理
                                projectLifecycleManager.handleProjectUploadAndCleanup(
                                        String.valueOf(userId),
                                        String.valueOf(appId),
                                        sessionId,
                                        localTempPath,
                                        (String message) -> log.info("Vue项目生命周期处理成功，appId: {}, message: {}", appId, message),
                                        (Exception e) -> log.error("Vue项目生命周期处理失败，appId: {}, error: {}", appId, e.getMessage(), e)
                                );

                                log.info("Vue项目构建成功，已启动生命周期管理，appId: {}", appId);
                                sink.complete();
                            } catch (BusinessException e) {
                                // 构建失败，直接传递BusinessException给前端
                                log.error("Vue项目构建失败: {}", e.getMessage(), e);
                                sink.error(e);
                            } catch (Exception e) {
                                // 其他异常，包装为BusinessException
                                log.error("Vue项目构建过程中发生未知错误: {}", e.getMessage(), e);
                                BusinessException businessException = new BusinessException(ErrorCode.SYSTEM_ERROR, "项目生成过程中遇到了一些问题，请稍后重试");
                                sink.error(businessException);
                            }
                        }
                    })
                    .onError((Throwable error) -> {
                        log.error("处理 TokenStream 时出错: {}", error.getMessage(), error);
                        sink.error(error);
                    })
                    .start();
            // 监听下游取消事件
            sink.onCancel(() -> {
                interrupted.set(true);
                log.info("TokenStream 被中断，appId: {}", appId);
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "应用被意外中断，可以稍后重试");
            });
        });
    }

    /**
     * 处理代码流，收集完整代码并保存（流式）
     * @param codeStream 代码流
     * @param codeGenType 代码生成类型
     * @param appId 应用 ID
     * @return 流式数据
     */
    private Flux<String> processCodeStream(Flux<String> codeStream, CodeGenTypeEnum codeGenType, Long appId) {
        // 字符串拼接器，用于当流式返回所有的代码之后，再保存代码
        StringBuilder codeBuilder = new StringBuilder();

        // 实时收集代码片段
        return codeStream.doOnNext(codeBuilder::append).doOnComplete(() -> {
            try {
                String completeCode = codeBuilder.toString();
                if (completeCode.trim().isEmpty()) {
                    log.warn("生成的代码为空，跳过文件保存，appId: {}", appId);
                    return;
                }
                // 解析代码为对象
                Object parsedResult = CodeParserExecutor.executeParser(completeCode, codeGenType);
                // 使用执行器保存代码
                Long userId = getUserIdByAppId(appId);
                CodeSaveResult saveResult = CodeFileSaverExecutor.executeSaver(parsedResult, codeGenType, appId, userId);
                log.info("代码已保存至目录: {}, appId: {}", saveResult.getAbsolutePath(), appId);
            } catch (Exception e) {
                log.error("解析或保存代码时出错，appId: {}, error: {}", appId, e.getMessage(), e);
            }
        });
    }

    /**
     * 生成应用名称
     *
     * @param initPrompt 用户的初始描述
     * @return 生成的应用名称
     */
    public String generateAppName(String initPrompt) {
        // 使用专门的应用名称生成服务，避免历史对话污染
        AiCodeGeneratorService aiCodeGeneratorService = aiCodeGeneratorServiceFactory.getAppNameGeneratorService();
        return aiCodeGeneratorService.generateAppName(initPrompt);
    }

    /**
     * 判断用户是否为管理员或VIP
     * @param user 用户对象
     * @return 是否为管理员或VIP
     */
    private boolean isAdminOrVip(User user) {
        if (user == null) {
            return false;
        }
        String userRole = user.getUserRole();
        return UserRoleEnum.ADMIN.getValue().equals(userRole) || 
               UserRoleEnum.VIP.getValue().equals(userRole);
    }

    /**
     * 计算消息的Token数量（简化实现）
     * 实际项目中可以使用更精确的Token计算库
     * @param message 消息内容
     * @return Token数量
     */
    private int calculateTokenCount(String message) {
        if (message == null || message.isEmpty()) {
            return 0;
        }
        // 简化计算：1个中文字符约等于2个Token，1个英文字符约等于0.75个Token
        int chineseCount = 0;
        int englishCount = 0;

        for (char c : message.toCharArray()) {
            if (c >= 0x4e00 && c <= 0x9fff) {
                chineseCount++;
            } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
                englishCount++;
            }
        }

        return (int) (chineseCount * 2 + englishCount * 0.75);
    }

    /**
     * 根据 appId 获取用户ID
     * @param appId 应用ID
     * @return 用户ID
     */
    private Long getUserIdByAppId(Long appId) {
        if (appId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "应用ID不能为空");
        }
        App app = appService.getById(appId);
        if (app == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "应用不存在");
        }
        return app.getUserId();
    }
}
